import { GameConfig } from "../configs/GameConfig"
import { Attribute } from "../etc/Attribute"
import { Bezier } from "../etc/Bezier"
import { Constants } from "../etc/Constants"
import { Tween } from "../etc/Tween"
import { util } from "../etc/Util"
import { CharacterTalk } from "../gameEtc/CharacterTalk"
import Appearance from "../model/Appearance"
import { NewRecodeTips } from "../ui/NewRecodeTips"
import { Notice } from "../ui/Notice"
import { VelocityEffect } from "../ui/VelocityEffect"
import { GuiModuleC } from "./GuiModule"
import { EnumBagItemGrid, ItemModuleData } from "./ItemModule"
import { PlayerModuleC, PlayerModuleS } from "./PlayerModule"
import { TerrainModuleC } from "./TerrainModule"

export class GameplayModuleData extends Subdata{
    @Decorator.persistence()
    maxDistance:number = 0
}

export class GameplayModuleC extends ModuleC<GameplayModuleS, GameplayModuleData>{
    // 玩家站立高度
    private readonly characterGroundZ = 134
    // 被扔后延迟多久重置
    private readonly fall2GroundDelaySecond = 2
    // 抛物线函数次方
    private readonly throwPow = 0.7

    // 在点击投掷时确认
    private throwDistanceInThisTime = 0
    private get secondThrowDistanceInThisTime():number{
        return this.throwDistanceInThisTime * 0.1
    }
    private get distanceAmount():number{
        return this.throwDistanceInThisTime + this.secondThrowDistanceInThisTime
    }
    private get distanceAmountMetreUnit():number{
        return Math.floor(this.distanceAmount / 2500 * 25)
    }

    canThrow:boolean = true

    private playerMD:PlayerModuleC
    private itemData:ItemModuleData

    private heldCharacter:Character
    private interactor:Interactor
    private secondCamera:Camera
    private mainCamera:Camera
    private playedTailEffectID:number
    
    private flyStartPosition:Vector
    private flyMiddlePosition:Vector
    private flyEndPosition:Vector
    private flyProcess1 = new Tween<{t:number}>({t:0})
        .to({t:1})
        .easing((x)=>{ return Math.pow(x, this.throwPow)})
        .onStart(()=>{
            // 切换摄像头
            this.secondCamera.worldTransform = this.mainCamera.worldTransform
            this.secondCamera.worldTransform.rotation = new Rotation(0,0,0)
            Camera.switch(this.secondCamera)
            // 速度线
            UIService.show(VelocityEffect)
        })
        .onUpdate(obj=>{
            // 角色飞行
            let bezierPosition = Bezier.evaluate_2l(this.flyStartPosition, this.flyMiddlePosition, this.flyEndPosition, obj.t)
            this.interactor.worldTransform.position = bezierPosition
            // 摄像机跟随
            this.setSecondCameraFollowHeldCharacter()
        })
        .onComplete(()=>{
            this.heldCharacter.currentAnimation.stop()
        })

    private reboundStartPosition:Vector
    private reboundMiddlePosition:Vector
    private reboundEndPosition:Vector
    private flyProcess2 = new Tween<{t:number}>({t:0})
        .to({t:1})
        .easing((x)=>{ return Math.pow(x, this.throwPow)})
        .onStart(()=>{
            // 摔倒动画
            let rollAnimation = this.heldCharacter.loadAnimation('135141')
            rollAnimation.speed = (2 / (this.secondThrowDistanceInThisTime * 0.5 / 1000)) * 0.8
            rollAnimation.play()
            // 开启人物叨逼叨
            CharacterTalk.show(this.heldCharacter, util.getHeldCharacterTalkText())
            // 播放特效
            EffectService.playAtPosition('57200', this.reboundStartPosition)
        })
        .onUpdate(obj=>{
            // 角色飞行
            let bezierPosition = Bezier.evaluate_2l(this.reboundStartPosition, this.reboundMiddlePosition, this.reboundEndPosition, obj.t)
            this.interactor.worldTransform.position = bezierPosition
            // 摄像机跟随
            this.setSecondCameraFollowHeldCharacter()
        })
        .onComplete(()=>{
            this.heldCharacter.currentAnimation.stop()
            // 关闭速度线
            UIService.hide(VelocityEffect)
            // 关闭拖尾特效
            if(this.playedTailEffectID){
                EffectService.stop(this.playedTailEffectID)
                this.playedTailEffectID = undefined
            }
        })

    // 结算阶段
    private flyProcess3 = new Tween<{t:number}>({t:0})
        .to({t:1})
        .onStart(()=>{
            this.settleEarning(this.distanceAmount)
            this.markMaxDistance(this.distanceAmountMetreUnit)
        })
        .onComplete(()=>{
            this.resetHeldCharacter()
            CharacterTalk.hide()
        })
        .duration(this.fall2GroundDelaySecond * 1e3)

    private throwAreaUI:UIWidget
    private throwAreaTrigger:Trigger

    isInThrowArea:boolean = false
    onEnterOrLeaveThrowAreaEvent:Action = new Action

    protected onStart(): void {
        this.mainCamera = Camera.currentCamera
		this.secondCamera = GameObject.spawn("Camera")
		this.heldCharacter = <Character>GameObject.findGameObjectById('3A82E8DB')
		this.interactor = GameObject.spawn("Interactor")
        this.throwAreaTrigger = <Trigger>GameObject.findGameObjectById('2F5D87C3')
        this.throwAreaUI = <UIWidget>GameObject.findGameObjectById('3CCB5114')

        this.playerMD = ModuleService.getModule(PlayerModuleC)
        this.itemData = DataCenterC.getData(ItemModuleData)

        this.throwAreaTrigger.onEnter.add(this.onThrowAreaEnter.bind(this))
        this.throwAreaTrigger.onLeave.add(this.onThrowAreaLeave.bind(this))
        this.heldCharacter.setCollision(CollisionStatus.Off)
        this.interactor.enter(this.heldCharacter)
        this.resetHeldCharacter()
    }

    private onThrowAreaEnter(other:GameObject){
        if(!util.isSelfPlayer(other)) return
        this.isInThrowArea = true
        this.throwAreaUI.setVisibility(false)
        this.onEnterOrLeaveThrowAreaEvent.call()
    }

    private onThrowAreaLeave(other:GameObject){
        if(!util.isSelfPlayer(other)) return
        this.isInThrowArea = false
        this.throwAreaUI.setVisibility(true)
        this.onEnterOrLeaveThrowAreaEvent.call()
    }

    setSecondCameraFollowHeldCharacter(){
        // 摄像机跟随
        this.secondCamera.worldTransform.position = Vector.add(this.heldCharacter.worldTransform.position, new Vector(-900,0,150))
        this.secondCamera.worldTransform.rotation = new Rotation(0, -10, 0)
    }

    resetHeldCharacter(){
        Player.localPlayer.character.attachToSlot(this.interactor, HumanoidSlotType.Head)
		this.interactor.localTransform.position = new Vector(-37,-10,110)
        
		this.heldCharacter.localTransform.position = Vector.zero
		this.heldCharacter.localTransform.rotation = Rotation.zero

		let upborne = this.heldCharacter.loadAnimation('14757')
		upborne.loop = 0
		upborne.play()
        
		let grab = Player.localPlayer.character.loadAnimation('20257')
		grab.loop = 0
		grab.slot = AnimSlot.Upper
		grab.play()

        this.canThrow = true

		Camera.switch(this.mainCamera)
    }

    async throwCharacter(){
        // 是否在投掷区域内
        if(!this.isInThrowArea){
            Notice.showTopNotice('请进入投掷区域内投掷!!')
            return
        }
        // 是否正在进行中
        if(this.canThrow == false){
            Notice.showTopNotice('您的朋友正在飞行中~')
            return
        }
        
        this.canThrow = false
        // 玩家朝向投掷方向
        Player.localPlayer.character.lookAt(new Vector(100000,0,0))
        // 确定投掷距离
        this.throwDistanceInThisTime = this.playerMD.getAttr(Attribute.EnumAttributeType.power) + this.playerMD.getAttr(Attribute.EnumAttributeType.powerInTime)
        // 加一点随机值
        this.throwDistanceInThisTime = this.throwDistanceInThisTime + Math.floor(util.randomNegative() * (this.throwDistanceInThisTime * 0.1))
        
        console.warn(`投掷总距离:${this.distanceAmount.toFixed(0)}, (${this.distanceAmountMetreUnit}米)`);
        // 生成地图块
        let terrainMD = ModuleService.getModule(TerrainModuleC)
        terrainMD.generateTileTerrain(this.distanceAmount * 2)
		// 换到右手
		let currentWorldPosition = this.interactor.worldTransform.position
		let currentWorldRotation = this.interactor.worldTransform.rotation
		Player.localPlayer.character.attachToSlot(this.interactor, HumanoidSlotType.RightHand)
		this.interactor.worldTransform.position = currentWorldPosition
		this.interactor.worldTransform.rotation = currentWorldRotation
		// 播放投掷动画
		let animation = Player.localPlayer.character.loadAnimation('122438')
		animation.speed = 0.8
		animation.play()
		await TimeUtil.delaySecond(0.8)
		// 翻腾动画
		let rollAnimation = this.heldCharacter.loadAnimation('14648')
		rollAnimation.loop = 0
		rollAnimation.play()
        // 播放拖尾特效
        let effectVo = this.itemData.getItemByGrid(EnumBagItemGrid.tailEffect)
        if(effectVo){
            let effectCfg = GameConfig.TailEffect.getElement(effectVo.baseInfo.cfgID)
            let [t,r,s] = util.unpackTransformByNumberArray(effectCfg.TRS)
            this.playedTailEffectID = EffectService.playOnGameObject(effectCfg.GUID, this.heldCharacter, {
                slotType:effectCfg.Slot,
                position:t,
                rotation:r,
                scale:s,
                loopCount:0
            })
        }
		// 解除绑定
		this.interactor.parent = undefined
		this.interactor.worldTransform.rotation = Rotation.zero
		this.interactor.worldTransform.scale = Vector.one
		// 位移tween
		this.flyStartPosition = this.interactor.worldTransform.position
        this.flyEndPosition = Vector.add(this.flyStartPosition, new Vector(this.throwDistanceInThisTime, 0, 0))
        this.flyEndPosition.z = this.characterGroundZ
        this.flyMiddlePosition = Vector.lerp(this.flyStartPosition, this.flyEndPosition, 0.3)
        this.flyMiddlePosition.z += Vector.distance(this.flyStartPosition, this.flyEndPosition) * 0.6
        this.flyProcess1.duration(this.throwDistanceInThisTime * 0.5)
        // 弹跳tween
        this.reboundStartPosition = this.flyEndPosition
        this.reboundEndPosition = Vector.add(this.reboundStartPosition, new Vector(this.secondThrowDistanceInThisTime, 0, 0))
        this.reboundEndPosition.z = this.characterGroundZ
        this.reboundMiddlePosition = Vector.lerp(this.reboundStartPosition, this.reboundEndPosition, 0.3)
        this.reboundMiddlePosition.z += Vector.distance(this.reboundStartPosition, this.reboundEndPosition) * 0.6
        this.flyProcess2.duration(this.secondThrowDistanceInThisTime * 0.5)
        // 连接tween
        this.flyProcess2.chain(this.flyProcess3)
        this.flyProcess1.chain(this.flyProcess2)
        // 播放
        this.flyProcess1.start()
    }

    // 结算金币
    settleEarning(distance:number){
        this.server.net_settle_earning(distance)
        let guidMD = ModuleService.getModule(GuiModuleC)
        let position = InputUtil.projectWorldPositionToWidgetPosition(this.interactor.worldTransform.position).screenPosition
        guidMD.mainUI.showMoneyTransition(7,position)
    }

    // 记录玩家飞行最远距离
    markMaxDistance(distanceMetre:number){
        if(this.data.maxDistance > distanceMetre) return
        // 弹出新纪录
        UIService.show(NewRecodeTips).setInfo(distanceMetre)
        // 保存新纪录
        this.server.net_mark_max_distance(distanceMetre)
    }
}

export class GameplayModuleS extends ModuleS<GameplayModuleC, GameplayModuleData>{
    
    // 记录最远距离(米)
    net_mark_max_distance(distanceMetreUnit:number){
        if(this.currentData.maxDistance > distanceMetreUnit) return
        this.currentData.maxDistance = distanceMetreUnit
        this.currentData.save(true)

        let appearacne = Appearance.AppearanceMap.get(this.currentPlayerId)
        if(!appearacne) return
        appearacne.playerRank = distanceMetreUnit
    }

    // 结算收益
    net_settle_earning(distance:number){
        let playerMD = ModuleService.getModule(PlayerModuleS)
        let money = Math.floor(distance * Constants.DistanceEarningRate)
        playerMD.addPlayerAttr(this.currentPlayerId, Attribute.EnumAttributeType.money, money)
    }
}